Completed
Push — master ( cd9c80...73ba51 )
by Andres
38s
created

generate_decay.js ➔ calculateReaction   C

Complexity

Conditions 12
Paths 112

Size

Total Lines 66

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 12
c 2
b 0
f 0
nc 112
dl 0
loc 66
rs 5.5923
nop 5

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like generate_decay.js ➔ calculateReaction often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* eslint-env node */
2
/*jslint node: true */
3
'use strict';
4
5
let jsonfile = require('jsonfile');
6
7
let args = process.argv.slice(2);
8
9
let resources = jsonfile.readFileSync(args[0] + '/data/resources.json');
10
let elements = jsonfile.readFileSync(args[0] + '/data/elements.json');
11
12
for (let key in resources) {
13
  let resource = resources[key];
14
  if(resource.type.indexOf('isotope') === -1){
15
    continue;
16
  }
17
  if (resource.decay) {
18
    let ratioSum = 0;
19
    for (let decay in resource.decay.decay_types) {
20
      ratioSum += resource.decay.decay_types[decay].ratio;
21
      resource.decay.decay_types[decay].reaction = generateReaction(key, decay);
22
    }
23
    let difference = 1 - ratioSum;
24
    if (Math.abs(difference) > 1e-6) {
25
      throw new Error('Ratios add up to '.concat(1 - difference, ' for ', key));
26
    }
27
  }
28
}
29
30
function generateReaction(isotope, type) {
31
  switch (type) {
32
  case 'beta-':
33
    return calculateReaction(isotope, 1, 'e-', 1, 0);
34
  case '2beta-':
35
    return calculateReaction(isotope, 2, 'e-', 2, 0);
36
  case 'beta+':
37
    return calculateReaction(isotope, 1, 'e+', -1, 0);
38
  case '2beta+':
39
    return calculateReaction(isotope, 2, 'e+', -2, 0);
40
  case 'electron_capture':
41
    return calculateReaction(isotope, 1, null, -1, 0);
42
  case 'alpha':
43
    return calculateReaction(isotope, 1, 'He2+', -2, -4);
44
  case 'SF':
45
    // FIXME: not yet implemented
46
    return {};
47
  default:
48
    throw new Error('Unrecognized decay type: ' + type);
49
  }
50
}
51
52
function calculateReaction(isotope, number, particle, protonDifference, isotopeDifference) {
53
  let element = isotope.replace(/^[0-9]*/, '');
54
  let elementNumber = elements[element].number-1;
55
  let listElements = Object.keys(elements);
56
  let otherElement = listElements[elementNumber + protonDifference];
57
58
  let isotopeNumber = Number(isotope.replace(element, '')) + isotopeDifference;
59
  let product = isotopeNumber + otherElement;
60
61
  // We need all this convoluted logic to work around missing isotopes in the data set
62
  // essentially we look for the closest isotope to the target one, and consume/produce
63
  // free neutrons in the process
64
  let distance = 0;
65
  if(!resources[product]){
66
    let candidate = null;
67
    // first we start looking for lighter isotopes
68
    for(let otherNumber = isotopeNumber; otherNumber > 0; otherNumber--){
69
      let otherProduct = otherNumber + otherElement;
70
      if(resources[otherProduct]){
71
        candidate = otherProduct;
72
        distance = isotopeNumber-otherNumber;
73
        break;
74
      }
75
    }
76
    // pay attention to the upper bound. 300 is bigger than any known isotope, so it is safe
77
    for(let otherNumber = isotopeNumber; otherNumber < 300; otherNumber++){
78
      let otherProduct = otherNumber + otherElement;
79
      if(resources[otherProduct]){
80
      // we only replace the candidate if the distance is smaller
81
      if(isotopeNumber-otherNumber < Math.abs(distance)){
82
          candidate = otherProduct;
83
          distance = isotopeNumber-otherNumber;
84
        }
85
        break;
86
      }
87
    }
88
    if(!candidate){
89
      throw new Error('No candidate found for '+isotope+' replacing the missing isotope '+product);
90
    }
91
    product = candidate;
92
  }
93
  let energy = resources[isotope].energy - resources[product].energy;
94
  if(distance < 0){
95
    energy -= resources.n.energy*distance;
96
  }
97
98
  let reaction = {};
99
  reaction.reactant = {};
100
  reaction.reactant[isotope] = number;
101
  // if the isotope is heavier, the distance is negative and we produce neutrons
102
  if(distance < 0){
103
    reaction.reactant.n = Math.abs(distance);
104
  }
105
  reaction.product = {};
106
  reaction.product[product] = number;
107
  if(particle){
108
    reaction.product[particle] = number;
109
  }
110
  // if the isotope is lighter, the distance is positive and we produce neutrons
111
  if(distance > 0){
112
    reaction.product.n = distance;
113
  }
114
  reaction.product.eV = energy;
115
116
  return reaction;
117
}
118
119
jsonfile.writeFileSync(args[0] + '/data/resources.json', resources, {
120
  spaces: 2
121
});
122
123
//console.log(JSON.stringify(originalElements, null,2))
124